package main

import (
	"encoding/csv"
	"fmt"
	"fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/driver/desktop"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/theme"
	"image/color"
	"io"
	"log"
	"os"
	"os/exec"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/widget"
	"github.com/faiface/beep"
	"github.com/faiface/beep/mp3"
	"github.com/faiface/beep/speaker"
)

// 默认25分钟
var defaultDuration = 25
var logger *log.Logger
var startButton *widget.Button

const doubleClickTimeout = 1000 * time.Millisecond

// 打包命令：
// windows平台：   fyne package --name My番茄钟 -os windows -icon resources/icon.png
// 安卓平台：      fyne package --name My番茄钟 -os android -icon resources/icon.png -appID com.zx.My番茄钟

func main() {
	// 初始化日志记录器
	initLogger("app.log")

	logger.Println("程序开始启动")

	// 创建一个新的应用程序
	myApp := app.New()

	// 创建一个窗口
	myWindow := myApp.NewWindow("My番茄钟")

	icon, err := fyne.LoadResourceFromPath("resources/icon.png")
	if err != nil {
		logger.Println("无法加载图标文件:", err)
	} else {
		myWindow.SetIcon(icon) // 设置窗口图标
	}

	// 设置窗口大小
	myWindow.Resize(fyne.NewSize(400, 250))
	//窗口居中
	myWindow.CenterOnScreen()
	// 设置系统托盘
	addSystemTray(myApp, myWindow)

	timeLabel := canvas.NewText(fmt.Sprintf("%02d:00", defaultDuration), color.Black)
	// 标签内容居中
	timeLabel.Alignment = fyne.TextAlignCenter
	timeLabel.TextSize = 56 // 设置字体大小为 36
	// 设置字体大小
	timeLabel.TextStyle = fyne.TextStyle{
		Bold:   true, // 加粗
		Italic: false,
	}

	// 多个时间可选。选中后，修改默认时间。
	b1 := widget.NewButton("1分钟", func() {
		defaultDuration = 1
		triggerBut(timeLabel, myApp, defaultDuration)
	})
	b2 := widget.NewButton("5分钟", func() {
		defaultDuration = 5
		triggerBut(timeLabel, myApp, defaultDuration)
	})
	b3 := widget.NewButton("10分钟", func() {
		defaultDuration = 10
		triggerBut(timeLabel, myApp, defaultDuration)
	})
	b4 := widget.NewButton("25分钟", func() {
		defaultDuration = 25
		triggerBut(timeLabel, myApp, defaultDuration)
	})
	b5 := widget.NewButton("40分钟", func() {
		defaultDuration = 40
		triggerBut(timeLabel, myApp, defaultDuration)
	})
	b6 := widget.NewButton("60分钟", func() {
		defaultDuration = 60
		triggerBut(timeLabel, myApp, defaultDuration)
	})

	// 将按钮放在同一行
	Container1 := container.New(
		layout.NewGridLayout(3), // 两列布局
		b1, b2, b3, b4, b5, b6,
	)

	// 输入框
	entry := widget.NewEntry()
	entry.SetPlaceHolder("请为本次专注请个标题[可以为空]")

	//进度条
	progress := widget.NewProgressBar()
	progress.SetValue(0.0)

	// 创建一个开始按钮
	startButton = widget.NewButton("开始", func() {
		go startPomodoro(timeLabel, myApp, defaultDuration, progress, entry.Text)
	})

	// 创建一个重置按钮
	//resetButton = widget.NewButton("重置", func() {
	//	triggerBut(timeLabel, myApp, defaultDuration)
	//})

	// 将按钮放在同一行
	Container2 := container.New(
		layout.NewGridLayout(1), // 两列布局
		startButton,
		//resetButton,
	)
	// 将标签和按钮添加到窗口中
	myWindow.SetContent(container.NewVBox(
		entry,
		Container1,
		timeLabel,
		progress,
		Container2,
	))

	logger.Println("程序启动完成")

	addWindowsMenu(myApp, myWindow)

	// 显示窗口并运行应用程序
	myWindow.ShowAndRun()

	logger.Println("程序退出")
}

func triggerBut(timeLabel *canvas.Text, myApp fyne.App, defaultDuration int) {
	//myApp.SendNotification(fyne.NewNotification("My番茄钟", "时间更新"))
	timeLabel.Text = fmt.Sprintf("%02d:00", defaultDuration)
}

func startPomodoro(timeLabel *canvas.Text, app fyne.App, defaultDuration int, progress *widget.ProgressBar, title string) {
	// 禁用开始按钮，防止重复点击
	startButton.Disable()
	defer startButton.Enable()

	// 设置My番茄钟的时间为1分钟
	duration := time.Duration(defaultDuration)*time.Minute + time.Second

	begin := time.Now()

	// 定义时间格式
	const layout = "2006-01-02 15:04:05" // Go 的时间格式是固定的，这个布局表示了参考时间 Mon Jan 2 15:04:05 MST 2006

	// 记录结束时间
	endTime := time.Now().Add(duration)

	// 创建一个Ticker来每秒更新一次时间
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()

	// 只能在主线程中更新 UI
	for {
		select {
		case <-ticker.C:
			// 计算剩余时间
			remaining := time.Until(endTime)
			if remaining <= 0 {
				// 在主线程中更新 UI
				app.SendNotification(fyne.NewNotification("My番茄钟", "时间到！休息一下！"))
				timeLabel.Text = "时间到！休息一下！"

				progress.SetValue(1)
				progress.Refresh()

				end := time.Now()

				// 追加数据到CSV文件
				records := [][]string{
					{
						begin.Format(layout),
						end.Format(layout),
						fmt.Sprintf("%d", defaultDuration),
						title,
					},
				}
				if err := appendToCSV("data.csv", records); err != nil {
					logger.Println(err)
				} else {
					logger.Println("数据成功追加到CSV文件中")
				}

				playSound() // 播放声音

				return
			}
			minutes := int(remaining.Minutes())
			seconds := int(remaining.Seconds()) % 60
			timeContent := fmt.Sprintf("%02d:%02d", minutes, seconds)
			//logger.Println("剩余时间：", timeContent)
			// 在主线程中更新 UI
			//app.SendNotification(fyne.NewNotification("My番茄钟", "时间更新"))
			timeLabel.Text = timeContent
			timeLabel.Refresh() // 刷新文本内容

			t1 := float64(duration.Nanoseconds())
			t2 := float64(remaining.Nanoseconds())
			p := (t1 - t2) / t1
			//logger.Println("百分比：", p)
			progress.SetValue(p)
			progress.Refresh()

		}
	}

}

// 播放声音
func playSound() {
	f, err := os.Open("resources/万里の長城_-_太田美知彦.mp3")
	if err != nil {
		logger.Println("无法加载声音文件:", err)
		log.Println(err)
		return
	}
	defer f.Close()

	streamer, format, err := mp3.Decode(f)
	if err != nil {
		log.Println(err)
		return
	}
	defer streamer.Close()

	// 初始化音频系统
	speaker.Init(format.SampleRate, format.SampleRate.N(time.Second))

	// 播放声音[这里是异步播放]
	speaker.Play(beep.Seq(streamer, beep.Callback(func() {
		logger.Println("播放完成")
	})))

	// 等待播放完成
	time.Sleep(24 * time.Second) // 可以根据需要调整等待时间
}

func appendToCSV(filename string, records [][]string) error {
	// 使用 os.OpenFile 函数以追加模式 (os.O_APPEND) 打开文件。
	// 如果文件不存在，则创建文件 (os.O_CREATE)，并且设置文件权限为 0644（只有文件所有者和所属组可以读写，其他人只能读）
	file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return fmt.Errorf("无法打开文件: %v", err)
	}
	defer file.Close()

	writer := csv.NewWriter(file)
	defer writer.Flush()

	for _, record := range records {
		if err := writer.Write(record); err != nil {
			return fmt.Errorf("无法写入记录: %v", err)
		}
	}

	return nil
}

func initLogger(filename string) {
	// 以追加模式打开日志文件，如果文件不存在则创建
	file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Println("无法打开日志文件: %v", err)
	}

	// 创建一个 io.MultiWriter，它将日志同时写入文件和控制台
	multiWriter := io.MultiWriter(file, os.Stdout)

	// 创建一个新的日志记录器，并设置其输出为 MultiWriter
	// 设置输出为文件，前缀为空，标志为默认（包含时间戳等）
	logger = log.New(multiWriter, "", log.LstdFlags)
}

// 系统托盘
func addSystemTray(a fyne.App, w fyne.Window) {
	if desk, ok := a.(desktop.App); ok {
		// 创建一个菜单项
		mOpen := fyne.NewMenuItem("打开窗口", func() {
			w.Show() /* 显示窗口 */
		})
		mOpen.Icon = theme.HomeIcon()
		// 创建一个菜单项
		mQuit := fyne.NewMenuItem("退出", func() {
			a.Quit()
		})
		mQuit.Icon = theme.CancelIcon()

		// 创建一个菜单，添加菜单项
		m := fyne.NewMenu("My番茄钟",
			mOpen, mQuit)

		// 将菜单设置为系统托盘菜单
		desk.SetSystemTrayMenu(m)

	}

	// 拦截窗口关闭事件，隐藏而不是退出
	w.SetCloseIntercept(func() {
		w.Hide()
	})
}

func addWindowsMenu(a fyne.App, w fyne.Window) {
	// 创建菜单
	fileMenu := fyne.NewMenu("文件")
	openRecordItem := fyne.NewMenuItem("打开记录", func() {
		openCurrentDirectory(w)
	})
	fileMenu.Items = append(fileMenu.Items, openRecordItem)

	mainmenu := fyne.MainMenu{}
	mainmenu.Items = append(mainmenu.Items, fileMenu)

	w.SetMainMenu(&mainmenu)
}

func openCurrentDirectory(w fyne.Window) {
	// 获取当前目录
	currentDir, err := os.Getwd()
	if err != nil {
		dialog.ShowError(err, w)
		return
	}

	// 执行打开资源管理器的命令
	cmd := exec.Command("explorer.exe", currentDir)
	err = cmd.Start()
	if err != nil {
		dialog.ShowError(fmt.Errorf("无法打开资源管理器: %w", err), w)
	}
}
